import tkinter as tk
from tkinter import messagebox

import numpy as np

import MCTS
import time
#加载引擎


MCTS.loadEngine(1,"model/RNG64_157.tf")
#参数

p=0.7
n=2

MCTS.setN(50)
MCTS.setF(1.6,1.2)
MCTS.valueWt=MCTS.num_simul
#界面
root=tk.Tk(className='五子棋')
boolvar=tk.IntVar()
#设置窗口大小
dxwidget=90
dx=34
pce=int(dx/2.3)
sar=int(dx/10)
hdx=dx//2
barcenter=int(dx*19.5)
barlength=int(dx*1.25)
x3=0
y3=0
gameover=0#判断游戏是否结束
isfree=True#当前位置是否可下
mvlst=[]#记录最后一步
nblst=[]#描绘棋子图像中的数字
pllst=[]#下过点的位置 [px,py]
evlst=[]#描绘胜率列表
brlst=[]#绘制胜率的柱状体
filled=[[0 for _ in range(15)] for __ in range(15)]#判断该位置是否可以下
root.geometry("%dx%d"%(18*dx+30,21*dx+60))#设置显示
canvas=tk.Canvas(root,width=18*dx,height=21*dx,bg="peru")#设置画布
canvas.place(x=10,y=40)
#绘制胜率
def redrawEval():
    global brlst
    for brs in brlst:
        canvas.delete(brs)
    nbs=len(evlst)
    brlst=[]
    if(nbs==0):
        return
    brwd=min(dx//2,dx*14//nbs)
    for ii in range(nbs):
        ddy=((evlst[ii]-0.5)*2*barlength) if ii%2==0 else ((0.5-evlst[ii])*2*barlength)
        if(ddy>=1 or ddy<= -1):
            brlst.append(canvas.create_rectangle(dx*2+brwd*ii,barcenter,dx*2+brwd*(ii+1),barcenter-ddy,fill="gray35" if ddy>0 else "gray70"))
        else:
            brlst.append(canvas.create_line(dx*2+brwd*ii,barcenter,dx*2+brwd*(ii+1),barcenter,fill="black"))
#悔棋
def takeBack():
    global gameover
    if(len(mvlst)<1):
        print("Cannot take back!")
        return
    canvas.delete(mvlst[-1])
    canvas.delete(nblst[-1])
    filled[pllst[-1][0]][pllst[-1][1]]=0
    mvlst.pop()
    pllst.pop()
    nblst.pop()
    evlst.pop()
    redrawEval()
    if(gameover):
        canvas.bind("<Button-1>",playStone)
        btmEval.config(state='normal')
        gameover=0
    MCTS.takeBack()
    MCTS.printBoard(MCTS.board)
    print("%d to move; %3d moves played."%(MCTS.side2move,MCTS.move_count))
#开始新的一步棋
def newGame():
    global gameover,evlst,nblst,pllst,mvlst,filled
    if(len(mvlst)<1):
        print("Cannot take back!")
        return
    for obj in mvlst:

        canvas.delete(obj)
    for obj in nblst:
        canvas.delete(obj)
    filled=[[0 for _ in range(15)] for __ in range(15)]#标识棋盘
    global totaltime
    totaltime=0
    mvlst=[]
    pllst=[]
    nblst=[]
    evlst=[]
    redrawEval()
    if(gameover):
        canvas.bind("<Button-1>",playStone)
        btmEval.config(state='normal')
        gameover=0
    MCTS.side2move=0
    MCTS.move_count=0
    MCTS.board*=0
    MCTS.states={}
    MCTS.printBoard(MCTS.board)
    print("%d to move; %3d moves played."%(MCTS.side2move,MCTS.move_count))
#下棋 设置变量状态
def playStoneXY(px,py,evalu=0.5):
    global gameover,x3,y3
    if(px<0 or px>14 or py<0 or py>14):
        return
    print("play",px,py)
    if (MCTS.move_count == 2):
        x3 = px
        y3 = py
    if(filled[px][py]):
        print("Non empty!")
        return 1
    else:
        with open('test.txt', 'a', encoding='utf-8') as f:
            if(MCTS.side2move==0):
             text ="("+"B "+str(px)+","+str(py)+")"
            else :
             text="("+"W "+str(px)+","+str(py)+")"
            f.write(text)
        filled[px][py]=1
        mvlst.append(canvas.create_oval(dx*(py+2)-pce,dx*(px+2)-pce,dx*(py+2)+pce,dx*(px+2)+pce,width=2,fill="white" if MCTS.move_count%2==1 else "black"))
        nblst.append(canvas.create_text(dx*(py+2),dx*(px+2),text=str(MCTS.move_count+1),fill="red" if MCTS.move_count%2==1 else "cyan"))
        pllst.append([px,py])
        evlst.append(evalu)
        redrawEval()
        MCTS.applyMove(px*15+py)
        MCTS.printBoard(MCTS.board)
        print("%d to move; %3d moves played."%(MCTS.side2move,MCTS.move_count))
        if(MCTS.winLossDraw()!=-1):
            print("game over!")
            root.update()
            messagebox.showinfo(master=root,message="Game Over!")
            gameover=1
            canvas.unbind("<Button-1>")
            btmEval.config(state='disabled')
            return 1
    return 0
#电脑下棋通过MCTSAI
def ComputerMove():
    print("Computer thinking...")
    MCTS.timeReset()
    global p
    #返回胜率和下的点的位置和深度
    # mp.freeze_support()
    # mvs=[]
    # dpts=[]
    # p = mp.Pool(10)  # 10个进程
    # for i in range(50):  # 50个待执行任务
    #     p.apply_async(MCTS.run_mcts, args=(MCTS.evaluatePositionA,False),callback=A.extend)
    # p.close()
    # p.join()
    mv,dpt=MCTS.run_mcts(MCTS.evaluatePositionA,False)
    if(MCTS.side2move==1):
        print("%3d X %2d %2d %.3f, d %2d"%(MCTS.move_count,mv[0]//15,mv[0]%15,mv[2],dpt))
    else:
        print("%3d O %2d %2d %.3f, d %2d"%(MCTS.move_count,mv[0]//15,mv[0]%15,mv[2],dpt))

    if (MCTS.move_count == 3):
        print("是否交换？")
        print("comuputer thinking")
        if(filled[7][7]*0.01+filled[7][6]*0.03+0.01*filled[7][8]*0.01>p):
            print("交换")
            return
        else:
            print("不需要交换")





    if (MCTS.move_count == 4):
        print("若有冲突点从这些点备选 或者反转 x,y（5，5），（5，8）  ")
        print(" ")
        print(" ")
        print(" ")
        print(" ")
        print(" ")
        print(" ")
        print(" ")
        print(" ")
        print(" ")
        print(" ")
        print(" ")
        print("打点有如下黑色的点")
        listx=[]
        for i in range(n):
            x=mv[0]//15+i
            y=mv[0]%15-i
            if(filled[x][y]!=1):
             print("（" + str(x) + "," + str(y) + ")", end=" ")
             listx.append((x,y))
            else:
             x=mv[0]//15-i+2
             y=mv[0]%15+i
             print("（" + str(x) + "," + str(y)+")",end=" ")
             listx.append((x, y))




        print(" ")
        print(" ")
        print(" ")
        print(" ")
        print(" ")
        print(" ")

        time.sleep(1)
        x1 = input("x:")
        y1 = input("y:")
        playStoneXY(int(x1), int(y1), mv[2])
        return



    MCTS.printTime()
    playStoneXY(mv[0]//15,mv[0] % 15,mv[2])
#鼠标点击事件
def playStone(event):
    global isfree
    if(not isfree): 
        print("Do not pre-move!")
        return
    isfree=False
    px,py=(event.y+hdx)//dx-2, (event.x+hdx)//dx-2
    ban1 = MCTS.forbidden(px, py)


    if ban1 == 1 or ban1 == 3 or ban1 == 4:
        print("禁手!!,黑棋胜利", px, py, ban1)
        messagebox.showinfo(master=root, message="Game Over!,黑棋禁手，白棋胜利")
    if(playStoneXY(px,py)==0):
        if(boolvar.get()):
            root.update()

            ComputerMove()
    isfree=True

#打点
def change(xx1):
    global n,x3,y3
    lstt = xx1.split()
    x=[]
    y=[]
    xmin =float(lstt[0])
    ymin = float(lstt[1])
    print(x3)
    print(y3)
    max=1;
    for i in range (n):
       x.append(float(lstt[i*2]));
       y.append(float(lstt[i*2+1]));
    x=np.array(x)
    y=np.array(y)
    print(x[0])
    print(y)
    for i in range(n):
       if(((xmin-x3)*(xmin-x3)+(ymin-y3)*(ymin-y3))<((x[i]-x3)*(x[i]-x3)+(y[i]-y3)*(y[i]-y3))):
           max=i+1;
           xmin=x[i]
           ymin=y[i]
    print("根据当前局面打点：")

    print("第"+str(max)+"个点")


def changeNNode(xx1):
    global nsu,fpun,fpur,wtt
    lstt=xx1.split()
    try:
        nsu=int(lstt[0])
    except:
        print("Bad cmd!")
    if(nsu>0):
        MCTS.setNumSimul(nsu)
    else:
        print("Illegal number of nodes!")

    try:
        fpun,fpur=float(lstt[1]),float(lstt[2])
    except:
        print("Bad cmd!")
    if(fpun>=0.5 and fpun<=2.0 and fpur>=0.5 and fpur<=2.0):
        MCTS.setFPU(fpun,fpur)
    else:
        print("Illegal FPU!")

    try:
        wtt=float(lstt[3])
    except:
        print("Bad cmd!")
    if(wtt>0):
        MCTS.valueWt=wtt*MCTS.num_simul
        print("value weight set to",wtt)
    else:
        print("Illegal number!")
#GUI设置按钮 AI下棋
btmEval=tk.Button(root,text="AI下棋",command=ComputerMove)
btmEval.place(x=10,y=10)
#自动下棋gui
autoPlay=tk.Checkbutton(root,text="自动下棋",variable=boolvar)
autoPlay.place(x=dxwidget+10,y=10)
autoPlay.toggle()
#悔棋
btmBack=tk.Button(root,text="悔棋",command=takeBack)
btmBack.place(x=dxwidget*2+10,y=10)
#新建一句游戏
btmNew=tk.Button(root,text="新开一局游戏",command=newGame)
btmNew.place(x=dxwidget*5.6+10,y=10)
entNod=tk.Entry(root,width=12)
entNod.place(x=dxwidget*4+10,y=10)

#设置参数设定
#entNod.insert(0,"%d %.1f %.1f %.1f"%(nsu,fpun,fpur,wtt))
btmSnd=tk.Button(root,text="打点 ",command=lambda:change(entNod.get()))
btmSnd.place(x=dxwidget*3+10,y=10)
#绑定鼠标单击事件
canvas.bind("<Button-1>",playStone)
#绘制棋盘
for i in range(15):
    canvas.create_line(dx*2,dx*(i+2),dx*16,dx*(i+2))
    canvas.create_line(dx*(i+2),dx*2,dx*(i+2),dx*16)
    canvas.create_text(dx,dx*(i+2),text=str(i))
    canvas.create_text(dx*17,dx*(i+2),text=str(i))
    canvas.create_text(dx*(i+2),dx,text=str(i))
    canvas.create_text(dx*(i+2),dx*17,text=str(i))
canvas.create_rectangle(dx*(7 +2)-sar,dx*(7 +2)-sar,dx*(7 +2)+sar,dx*(7 +2)+sar,fill="black")
canvas.create_rectangle(dx*(3 +2)-sar,dx*(3 +2)-sar,dx*(3 +2)+sar,dx*(3 +2)+sar,fill="black")
canvas.create_rectangle(dx*(3 +2)-sar,dx*(11+2)-sar,dx*(3 +2)+sar,dx*(11+2)+sar,fill="black")
canvas.create_rectangle(dx*(11+2)-sar,dx*(3 +2)-sar,dx*(11+2)+sar,dx*(3 +2)+sar,fill="black")
canvas.create_rectangle(dx*(11+2)-sar,dx*(11+2)-sar,dx*(11+2)+sar,dx*(11+2)+sar,fill="black")
for i in [-1,1]:
    canvas.create_line(dx*2,barcenter+i*barlength,dx*16,barcenter+i*barlength,fill="black")
root.mainloop()
